
/**
 * 深拷贝
 * @param {*} org 原始数据
 * @param {*} map map的使用，是为了避免循环引用的存在，如果不考虑可以去掉
 */
function deepClone(org, map = new Map()) {
    if(typeof org !== 'object' || org === null) 
        return org;
    if(map.get(org))
        return map.get(org);
    let is_array = Object.prototype.toString.call(org) === '[object Array]';
    let res = is_array ? [] : {};
    map.set(org, res)
    switch(org.constructor) {
        case Date:
        case RegExp:
            return new org.constructor(org);
            break;
        default:
            Object.keys(org).forEach(key => {
                res[key] = deepClone(org[key], map);
            });
    }
    return res;
}

/**
 * 时间格式化
 * @param {*} date 日期对象
 * @param {*} format 格式模板
 */
function formatTime(date, format='yyyy-MM-dd') {
    let weeks = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'];
    let map = {
        'y+' : date.getFullYear(),
        'M+': date.getMonth() + 1,
        'd+': date.getDate(),
        'h+': date.getHours(),
        'm+': date.getMinutes(),
        's+': date.getSeconds(),
        'w+': weeks[date.getDay()]
    };

    for(let key in map) {
        console.log("formatTime -> key", key)
        if(new RegExp(`(${key})`).test(format)) {
            const len = RegExp.$1.length;
            format = format.replace(RegExp.$1, len===1 ? map[key] : ('0'+map[key]).slice(-len))
        }
    }
    return format;
}

// console.log(formatTime(new Date(), 'yyyy-MM-dd hh:mm:ss www'))

/**
 * 一键复制
 * @param {*} selector 用于选中需要复制内容原生的选择器
 */
function handleCopy(selector) {
    const url = document.querySelector(selector);
    url.select(); // 选中内容
    document.execCommand('Copy'); // 调用复制命令
}

/**
 * 节流函数
 * 高频事件触发后一定时间内只会执行一次，重复触发重新计算（触发后取消之前的延时调用）。
 * 1.窗口resize, 可以使用节流的操作，没必要单位时间内响应用户操作。
 * 2.搜索输入，以及一些类似手机号等input的验证，仅需再用户输入完毕后进行处理。
 * @param {*} fn 
 * @param {*} wait 
 */
function debounce(fn, wait=500) {
    let timer = null
    return function() {
        if(timer) 
            clearTimeout(timer)
        timer = setTimeout(() => {
            fn.apply(this, arguments)
        }, wait);
    }
}

/**
 * 节流函数：支持立即执行参数
 * @param {*} fn 
 * @param {*} wait 
 * @param {*} immediate 是否立即执行
 */
function debounce(fn, wait=500, immediate=false) {
    let timer = null;
    return function() {
        if(timer)
            clearTimeout(timer)
        if(immediate) {
            let _timer = timer;
            timer = setTimeout(() => timer=null, wait);
            if(_timer)
                fn.apply(this, arguments);
        }else{
            timer = setTimeout(() => fn.apply(this.arguments), wait)
        }
    }
}

/**
 * 防抖函数：支持立即执行参数
 * 控制函数执行的频率（触发事件判断等待时间到了才执行一次，开始下一次周期的计时）
 * 1.游戏的mouseDown/keydown/touchMove等事件，单位时间内应该只执行一次
 * 2.DOM元素拖拽功能，canvas模拟画板功能，这类mousemove事件需要单位时间响应用户操作的处理。
 * 3.滚动事件的监听，比如页面滚动到底部加载更多。这个需要单位时间内去做一次判断。
 * @param {*} fn 
 * @param {*} wait 
 * @param {*} immediate 
 */

function throttle(fn, wait=500, immediate=false) {
    let lastTime = immediate ? 0 : Date.now();
    return function() {
        let curTime = Date.now();
        if(curTime - lastTime >= wait) {
            lastTime = Date.now(); // 注意，lastTime赋值需要放到fn执行之前，避免fn执行报错，节流失败
            fn.apply(this, arguments);
        }
    }
}

/**
 * 防抖函数 如果你非要我用timer写（利用timer作为计时的flag）
 * @param {*} fn 
 * @param {*} wait 
 * @param {*} immediate 
 */
function throttle(fn, wait=500, immediate=false) {
    let timer = null;
    return function() {
        if(!timer) {
            timer = setTimeout(() => {
                clearTimeout(timer);
                timer = null;
                immediate || fn.apply(this, arguments);
            }, wait);
            immediate && fn.apply(this, arguments);
        }
    }
}

// // blob转url
// axios({
//     url: '/share-poster-with-goods',
//     methods: 'get',
//     responseType: 'blob'
// }).then(res => {
//     this.img_src = window.URL.createObjectURL(res.data)
// })
// // blob转base64
// axios({
//   url: "/share-poster-with-goods",
//   methods: "get",
//   responseType: "blob"
// }).then(res => {
//   let a = new FileReader();
//   a.readAsDataURL(res.data);
//   a.onload = e => {
//     this.img_src = e.target.result;
//   };
// });

// // arraybuffer转base64, a标签使用base64地址下载时，download属性值为 xxx.png/jpeg（设置为jpg可能会出错）
// axios({
//   url: "/share-poster-with-goods",
//   methods: "get",
//   responseType: "arraybuffer"
// }).then(res => {
//   console.log(res, res);
//   this.img_src =
//     "data:image/jpg;base64," +
//     btoa(
//       new Uint8Array(res.data).reduce(
//         (data, byte) => data + String.fromCharCode(byte),
//         ""
//       )
//     );
// });